<script setup lang="ts">
import type { Raw, Component } from 'vue'
import { ref, reactive, markRaw, nextTick } from 'vue'
import { nextKey } from '../../util'
import type { ModalOptions } from './types'
import { fadeIn, fadeOut } from '../../effect'

type ModalItem = {
  component: Raw<Component>
  closeOnBackgroundClicked: boolean
  showCloseButton: boolean
  props: { [key: string]: any }
  events: { [event: string]: (...args: any) => void }
  key: string
}

const modals = reactive<ModalItem[]>([])
const modalContent = ref<HTMLElement[] | null>(null)

function elementOf(item: ModalItem): HTMLElement | null {
  const idx = modals.indexOf(item)
  return elementAt(idx)
}

function elementAt(idx: number): HTMLElement | null {
  const elements = modalContent?.value
  if (elements && idx >= 0 && idx < elements.length) {
    return elements[idx]
  }
  return null
}

function create(opts: ModalOptions): string {
  const item: ModalItem = {
    component: markRaw(opts.component),
    closeOnBackgroundClicked:
      opts.closeOnBackgroundClicked != null ? opts.closeOnBackgroundClicked : true,
    showCloseButton: opts.showCloseButton != null ? opts.showCloseButton : true,
    props: opts.props || {},
    events: Object.assign({}, opts.events),
    key: opts.key || nextKey()
  }
  modals.push(item)
  nextTick(() => {
    const e1 = elementOf(item)
    if (e1) {
      fadeIn(e1, 150)
    }
  })
  return item.key
}

function destroy(key: string) {
  const idx = modals.findIndex((item) => item.key === key)
  close(idx)
}

function backgroundClicked(idx: number) {
  const item = modals[idx]
  if (!item.closeOnBackgroundClicked) {
    return
  }
  close(idx)
}

async function close(idx: number) {
  if (idx < 0 || idx >= modals.length) {
    return
  }
  const item = modals[idx]
  const e = elementAt(idx)
  if (!e) {
    return
  }
  await fadeOut(e, 150)
  const i = modals.indexOf(item)
  modals.splice(i, 1)
}

defineExpose({
  create,
  destroy
})
</script>
<template>
  <div id="modal-container">
    <div v-for="(opt, idx) in modals" :key="opt.key" class="modal is-active">
      <div class="modal-background" @click="backgroundClicked(idx)" />
      <div class="modal-content" ref="modalContent" style="overflow: visible">
        <component
          :is="opt.component"
          class="modal-inner-content"
          v-bind="opt.props"
          v-on="opt.events"
          @hide="close(idx)"
          @close="close(idx)"
        />
        <button v-if="opt.showCloseButton" class="modal-close" @click="close(idx)" />
      </div>
    </div>
  </div>
</template>
